#include "xaudio_play.h"
#include <SDL.h>
#include <iostream>
extern "C" {
#include <libavformat/avformat.h>
}
class CXAudioPlay : public XAudioPlay {
public:
  CXAudioPlay() : XAudioPlay() {}
  ~CXAudioPlay() { Close(); }
  void Pause(bool is_pause) override {
    if (is_pause)
    {
        SDL_PauseAudio(1);
		pause_begin = NowMs();
    }
    else
    {
		if(pause_begin>0)
		    last_ms_ += (NowMs() - pause_begin);
        SDL_PauseAudio(0);
    }
  }
  bool Open(XAudioSpec &spec) override {
    spec_ = spec;
    Close();
    SDL_AudioSpec sdl_spec;
    sdl_spec.freq = spec.freq;
    sdl_spec.format = spec.format;
    sdl_spec.channels = spec.channels;
    sdl_spec.samples = spec.samples;
    sdl_spec.silence = 0;
    sdl_spec.userdata = this;
    sdl_spec.callback = &CXAudioPlay::AudioCallback;
    if (SDL_OpenAudio(&sdl_spec, nullptr) != 0) {
      std::cout << SDL_GetError() << std::endl;
    }
    SDL_PauseAudio(0);
    return true;
  }

  void Callback(unsigned char *stream, int len) override {
    SDL_memset(stream, 0, len);
    std::unique_lock<std::mutex> lock(mux_);
    if (audio_datas_.empty())
      return;
    //  1 buf大于stream缓冲 offset记录位置
    //  2 buf小于stream缓冲 拼接
    int mixde_size = 0;  // 已经处理的字节数
    int need_size = len; // 需要处理的字节数
    auto& buf = audio_datas_.front();
    cur_pts_ = buf.pts;
    while (mixde_size < len) {
      if (audio_datas_.empty())
        break;
      auto &buf = audio_datas_.front();
      //cur_pts_ = buf.pts;
      int size = buf.data.size() - buf.offset; // 剩余未处理的数据
      //  1 大于stream缓冲 offset记录位置
      if (size > need_size) {
        size = need_size;
      }
      SDL_MixAudio(stream + mixde_size, buf.data.data() + buf.offset, size,
                   volume_);
      buf.offset += size;
      need_size -= size;
      mixde_size += size;
      // 如果已经使用完来了，那么弹出
      if (buf.offset >= buf.data.size()) {
        audio_datas_.pop_front();
      }
    }
  }
  void Close() override {
    // 退出上一次打开的音频(先退出线程）
    SDL_QuitSubSystem(SDL_INIT_AUDIO);
    std::unique_lock<std::mutex> lock(mux_);
    audio_datas_.clear();
    cur_pts_ = 0;// 当前播放的帧的pts
    last_ms_ = 0; // 上一次的时间戳
    pause_begin = 0; // 暂停开始的时间戳
  }
  long long cur_pts()override {
      double ms = 0.;
      if (last_ms_ > 0) {
          ms = NowMs() - last_ms_;// 距离上一次写入缓冲的播放时间
      }
      // 换算成frame的时间（pts换算成毫秒）
      if(time_base_>0)
        ms = ms / 1000.0 / time_base_;
      return cur_pts_ + ms * speed_;
  }
private:
    long long cur_pts_ = 0;// 当前播放的帧的pts
    long long last_ms_ = 0; // 上一次的时间戳
    long long pause_begin = 0; // 暂停开始的时间戳
};

XAudioPlay *XAudioPlay::Instance() {
  static CXAudioPlay play;
  return &play;
}

void XAudioPlay::Push(AVFrame* frame)
{
    std::cout << "z" << std::endl;
    if (!frame)return;
    std::vector<unsigned char> buf;
    int sample_size = av_get_bytes_per_sample(AVSampleFormat(frame->format));
    int channels = frame->channels;
    unsigned char* data = nullptr;
    // 暂时支持双通道
    switch (frame->format)
    {
    case AV_SAMPLE_FMT_S16P:
    case AV_SAMPLE_FMT_S32P:
    case AV_SAMPLE_FMT_FLTP:
    {
        buf.resize(frame->linesize[0]);
        data = buf.data();
        std::vector<unsigned char*>datas;
        for (int i = 0; i < channels; ++i) {
            datas.push_back(frame->data[i]);
        }
        // 转换为交叉平片
        for (int i = 0; i < frame->nb_samples; ++i)
        {
            for (int j = 0; j < channels;++j) {
                memcpy(data + (i * channels +j) * sample_size ,
                    datas[j] + i * sample_size, sample_size);
            }
        }
        std::cout << "y" << std::endl;
        Push(data, frame->linesize[0],frame->pts);
        return;
        break;
    }
    default:
        break;
    }
    // 交叉格式
    std::cout << "x" << std::endl;
    Push(frame->data[0], frame->nb_samples*sample_size, frame->pts);
}

XAudioPlay::XAudioPlay() { SDL_Init(SDL_INIT_AUDIO); }

bool XAudioPlay::Open(AVCodecParameters* para) {
    XAudioSpec spec;
    spec.channels = para->channels;
    spec.freq = para->sample_rate;
    switch (para->format)
    {
    case AVSampleFormat::AV_SAMPLE_FMT_S16:
    case AVSampleFormat::AV_SAMPLE_FMT_S16P:
        spec.format = AUDIO_S16;
        break;
    case AVSampleFormat::AV_SAMPLE_FMT_S32:
    case AVSampleFormat::AV_SAMPLE_FMT_S32P:
        spec.format = AUDIO_S32;
        break;
    case AVSampleFormat::AV_SAMPLE_FMT_FLTP:
    case AVSampleFormat::AV_SAMPLE_FMT_FLT:
        spec.format = AUDIO_F32;
        break;
    default:
        break;
    }
    return Open(spec);
}

bool XAudioPlay::Open(XPara& para)
{
    if(para.time_base->den)
        set_time_base(static_cast<double>(para.time_base->num) / static_cast<double>(para.time_base->den));
    return Open(para.para);
}
